#include "rd522.h"
#include "rd522_if.h"

void rd522_rst(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;//EA I2C
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	
	
	GPIO_SetBits(GPIOB, GPIO_Pin_14);
	GPIO_ResetBits(GPIOB, GPIO_Pin_15);
	
	delay_ms(10);
	GPIO_ResetBits(GPIOA, GPIO_Pin_12);
	delay_ms(200);
	GPIO_SetBits(GPIOA, GPIO_Pin_12);
	delay_ms(200);
}

void rd522_config_analog(void)
{
//	write_reg(txmode_reg, 0x00);   							//配置发送编码格式typeA
//	write_reg(rxmode_reg, 0x00);							//配置接收编码格式typeA
	write_reg(rxgain_reg, 0x02);							//配置接收增益，0x00->最大，板级噪声较低时，可配置为最大，一般40db即可。
	write_reg(svl_reg, 0x40);                               //SVL建议配置0x10或0x20或0x40
//	write_reg(svhsvl_reg, 0x30);
	write_reg(modconductance_reg, 0x05);          			//MODCONDUCTANCE 凹槽载波调制深度 05
	write_reg(cwconductance_reg, 0x09);          			//p_CWCONDUCTANCE (09)
	set_bit_mask(0x36, BIT5);
//	printf("%02x\r\n", read_reg(0x35));
	
//	write_reg(0x38, 0x32); 
	
	write_reg(txcontrol_reg, 0x00);
	delay_ms(10);
	write_reg(txcontrol_reg, 0x1b);          				//TXCONTRL  100%调制  1b
	delay_ms(10);
#if RD522_DEBUG	
	printf("\r\n== [config_analog] ==\r\n");
	printf("txmode_reg:%02x\r\n",read_reg(txmode_reg));	
	printf("rxmode_reg:%02x\r\n",read_reg(rxmode_reg));	
	printf("rxgain_reg:%02x\r\n",read_reg(rxgain_reg));	
	printf("svl_reg_value:%02x\r\n",read_reg(svl_reg));
	printf("modconductance_reg_value:%02x\r\n",read_reg(modconductance_reg));
	printf("cwconductance_reg_value:%02x\r\n",read_reg(cwconductance_reg));
	printf("txcontrol_reg_value:%02x\r\n",read_reg(txcontrol_reg));
#endif
//printf("txcontrol_reg_value:%02x\r\n",read_reg(txcontrol_reg));
}

void rd522_set_rate(uint8_t rate,uint8_t wait_param) 
{
    switch(rate) 
	{
        case 0:
		    clear_bit_mask(txmode_reg, BIT4 | BIT5 | BIT6);
            clear_bit_mask(rxmode_reg, BIT4 | BIT5 | BIT6);
			write_reg(waitparam_reg, wait_param & 0x0f);	//帧等待寄存器,wait_param就是FWI
            break;
        case 1:
			clear_bit_mask(txmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(txmode_reg, BIT4);
            clear_bit_mask(rxmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(rxmode_reg, BIT4);
			write_reg(waitparam_reg, wait_param & 0x0f);	//帧等待寄存器,wait_param就是FWI
            break;
        case 2:
            clear_bit_mask(txmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(txmode_reg, BIT5);
            clear_bit_mask(rxmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(rxmode_reg, BIT5);
			write_reg(waitparam_reg, wait_param & 0x0f);	//帧等待寄存器,wait_param就是FWI
            break;
        case 3:
			clear_bit_mask(txmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(txmode_reg, BIT4 | BIT5);
            clear_bit_mask(rxmode_reg, BIT4 | BIT5 | BIT6);
            set_bit_mask(rxmode_reg, BIT4 | BIT5);
			write_reg(waitparam_reg, wait_param & 0x0f);	//帧等待寄存器,wait_param就是FWI
            break;
        default:
			clear_bit_mask(txmode_reg, BIT4 | BIT5 | BIT6);
            clear_bit_mask(rxmode_reg, BIT4 | BIT5 | BIT6);
            break;
    }
}

int8_t rd522_get_crc(unsigned char mode, unsigned char len, unsigned char *crc_src, unsigned char* crc_lsb, unsigned char* crc_msb)
{
    unsigned int i = 0;
	
    write_fifo(crc_src,len);                    	//写进FIFO要计算的crc的值
    write_reg(crcpreset_reg, mode);                 //CRC配初值
    write_reg(command_reg, 0x92);          		    //启动硬件计算CRC

    while((read_reg(divirq_reg) & 0x04) != 0x04)    //crc计算计数器
    {
        i++;

        if(i >= 0x5000)
        {
            i = 0;
#if RD522_DEBUG
			printf("crc error! \r\n");
#endif
            return MI_COM_ERR;
        }
    }

    *crc_lsb = read_reg(crclsb_reg);                 //CRC结果低8位
    *crc_msb = read_reg(crcmsb_reg);                 //CRC结果高8位

    return MI_OK;
}

int8_t rd522_data_transceive(rd522_buff_t *pi)
{
	int delay_conut = 0;
	int8_t status = MI_EMPTY;
	
	write_reg(fifolevel_reg, 0x80);                     //clear fifo data
	write_reg(recstate_reg, 0x7F);                      //清接收状态寄存器
	write_fifo(pi->data,pi->length);	 				//把数据写入FIFO
	write_reg(command_reg, pi->command | BIT7);  		//命令寄存器,正常模式下该寄存器最高位需置1

#if RD522_DEBUG
	int8_t i;
	printf("<< TX : ");
	for(i = 0;i < pi->length; i++ )
	{
		printf("%02x ",pi->data[i]);
	}
	printf("\r\n");		
#endif	
	
	if(PCD_AUTHENT == pi->command)
	{
		while((read_reg(status2_reg) & 0x0c) != 0x08) 
        { 
            delay_conut++;
            if(delay_conut >= 0x3000)
            {
				delay_conut = 0;
#if RD522_DEBUG
				printf("authent error! \r\n");
#endif
				write_reg(recstate_reg, 0x7F);
				return MI_AUTHERR;
            }
			
        }

//        write_reg(status2_reg, 0x08);//清除认证状态标志位
        return MI_OK;	
	}	
	else if(PCD_TRANSMIT == pi->command)
	{
		write_reg(recstate_reg, 0x7F);
		return MI_OK;
	}
	else
	{		
		while((read_reg(recstate_reg) & 0x01) != 0x01)//读接收状态寄存器
		{
			delay_conut++;
			if((delay_conut >= 0x3000) || ((read_reg(recstate_reg) & 0x04) == 0x04))
			{
				delay_conut = 0;
#if RD522_DEBUG
				printf("transceive error! \r\n");
				printf("recstate_reg: %02x\r\n", read_reg(recstate_reg));
#endif			
				
				write_reg(recstate_reg, 0x7F);
//				write_reg(command_reg, 0xbF);
				write_reg(rec_begin_bit_pos_reg, 0x00);
				return MI_ERR_RECEIVE;
			}
		}
//		RD522_SPI_CS_HIGH;
		if(read_reg(recstate_reg) & (BIT1))
		{
			pi->length  = read_reg(fifolevel_reg);//FIFO长度寄存器
			pi->data[0] = read_reg(collpos_reg);//获取冲突字节和比特的位置信息
			read_fifo(&pi->data[1],pi->length);
			status = MI_COLL;
		}
		else
		{
			pi->length  = read_reg(fifolevel_reg);//FIFO长度寄存器
			read_fifo(pi->data,pi->length);
			status = MI_OK;
		}
		write_reg(recstate_reg, 0x7F);

#if RD522_DEBUG
		printf(">> RX : ");
		for(i = 0;i < pi->length; i++ )
		{
			printf("%02x ",pi->data[i]);
			printf("\r\nlength = %d\r\n",pi->length);
		}
		printf("\r\n");
		return status;
#endif
	}
	return status;
}

void rd522_init(void)
{
	/**********初始化RD522RST引脚并复位RD522**********/
	rd522_rst();
	RST_RESET
	delay_ms(10);
	RST_SET
	delay_ms(10);
	/**********设置RD522RST有关参数和帧等待时长**********/
	rd522_config_analog();
	rd522_set_rate(RATE_106, 10);
	
	#if LPCD_ON
	write_reg(irqpinconfig_reg, 0x80);	//输出中断配置
	write_reg(interupen_reg, 0x80);	
	
	/* IRQ 引脚初始化*/
    ZKRD522_IrqPin_Config();    /* IRQ引脚配置 */
	#endif
}

